home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / audio / bz / bzsound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  24.6 KB  |  1,076 lines

  1. /*
  2.  * Copyright (C) 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /***************************************************************************
  18.  *
  19.  * @(#) - BZ - Multiplayer tank game - Sound support.
  20.  *
  21.  * $Id: bzsound.c,v 1.4 1993/08/11 19:46:39 adele Exp $
  22.  *
  23.  *                    Chris Fouts - Silicon Graphics, Inc.
  24.  *                    October, 1991
  25.  **************************************************************************/
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <fcntl.h>
  29. #include <errno.h>
  30. #include <sys/types.h>
  31. #include <sys/prctl.h>
  32. #include <string.h>
  33. #include <signal.h>
  34. #include <malloc.h>
  35. #include <unistd.h>
  36. #include <audio.h>
  37. #include <invent.h>
  38. #include <math.h>
  39.  
  40. #include "aiff.h"
  41. #include "bzsound.h"
  42.  
  43. #define ABS(x)    ( ( (x) < 0 ) ? -(x) : (x) )
  44.  
  45. static char    *version_id = "$Id: bzsound.c,v 1.4 1993/08/11 19:46:39 adele Exp $" ;
  46.  
  47.  
  48. typedef union 
  49. {
  50.     unsigned char b[2];
  51.     short         s;
  52. } align_short_t;
  53.  
  54. typedef union 
  55. {
  56.     unsigned char b[4];
  57.     long         l;
  58. } align_long_t;
  59.  
  60.  
  61. #define    MAX_EXP_DEPTH    5
  62. #define    MAX_EXP_ANGLE    3
  63. #define EXP_DELTA_ANGLE    ( M_PI / 4.0 )
  64. #define    EXP_DELTA_DEPTH    250.0
  65. #define    MAX_AUDIO_PORTS    3
  66.  
  67. extern char    *basename ;
  68. static unsigned long orig_left_gain ;
  69. static unsigned long orig_right_gain ;
  70. static unsigned long orig_output_rate ;
  71. static unsigned long curr_left_gain ;
  72. static unsigned long curr_right_gain ;
  73. static long sound_size[SFX_N_SOUNDS] ;
  74. static short *sound_data[SFX_N_SOUNDS] ;
  75. static char *sound_file[SFX_N_SOUNDS] = {
  76.         "mine_drop.aiff",
  77.         "mine_pick_up.aiff",
  78.         "explosion.aiff",
  79.         "fire.aiff",
  80.         "bump.aiff",
  81.         "pop.aiff",
  82.         "flag_grabbed.aiff",
  83.         "flag_won.aiff",
  84.         "flag_lost.aiff",
  85.         "pause.aiff",
  86.         } ;
  87. static long        explosion_size ;
  88. static short    *explosion_data[MAX_EXP_DEPTH][MAX_EXP_ANGLE] ;
  89. static short    *new_sound_data ;
  90. static long        new_sound_size ;
  91. static int        new_sound = 0 ;
  92. static char        *filename;             /* input file name */
  93. static int        bytes_per_samp;        /* sample width */
  94. static int        samps_per_frame;    /* frame size */
  95. static int        frames_per_sec;        /* sample rate */
  96. static ALport    audio_port[MAX_AUDIO_PORTS+1] ;/* foreground audio ports */
  97. static int        sound_child = 0 ;
  98. static int        sound_enabled = 0 ;
  99. static int        has_sound_hw = 0 ;
  100.  
  101.  
  102. static unsigned long    gain_settings[] =
  103.                             { 0, 2, 3, 5, 9, 16, 29, 50, 91, 156, 255 } ;
  104. static int                gain_index ;
  105.  
  106. int    pause( void ) ;
  107. /* BEGIN PROTOTYPES -S bzsound.c */
  108. static int      check_for_audio_hw( void ) ;
  109. static double   ConvertFromIeeeExtended( char *bytes ) ;
  110. static char    *init_audio( int fd, audio_params_t *audio_params,
  111.                     ssnd_chunk_t *ssnd_data, comm_chunk_t *comm_data,
  112.                     long *size ) ;
  113. static ALport   init_audio_port( int all ) ;
  114. static void     init_explosion_data( short *src_data, long src_size ) ;
  115. static char    *load_aiff_file( char *dir, char *name, long *size ) ;
  116. static char    *read_aiff_file( int fd, long *size ) ;
  117. static int      read_chunk_header( int fd, chunk_header_t *chunk_header ) ;
  118. static void     read_comm_chunk( int fd, comm_chunk_t *comm_data,
  119.                     audio_params_t *audio_params ) ;
  120. static void     read_form_chunk( int fd, chunk_header_t *chunk_header ) ;
  121. static void     read_ssnd_chunk( int fd, chunk_header_t *chunk_header,
  122.                     ssnd_chunk_t *ssnd_data ) ;
  123. static void     reset_audio_hw( void ) ;
  124. static void     set_gain( float l, float r ) ;
  125. static void     set_gain_index( unsigned long gain ) ;
  126. static void     signal_sound( short *data, long size ) ;
  127. static void     skip_chunk( int fd, chunk_header_t *chunk_header ) ;
  128. static void     sound_handler( void *arg ) ;
  129. static void     wake_up( int sig, int code, struct sigcontext *sc ) ;
  130. /* END PROTOTYPES -S bzsound.c */
  131.  
  132.  
  133. int init_sound( void )
  134. {
  135.     int    i ;
  136.     char *audio_dir ;
  137.  
  138.     if( ( has_sound_hw = check_for_audio_hw() ) != 0 ) {
  139.         if( ( audio_port[0] = init_audio_port( 1 ) ) == NULL ) {
  140.             fprintf( stderr, "%s: no audio ports available\n", basename ) ;
  141.             return( 1 ) ;
  142.             }
  143.  
  144.         if( ( audio_port[1] = init_audio_port( 0 ) ) != NULL ) {
  145.             audio_port[2] = init_audio_port( 0 ) ;
  146.             }
  147.         audio_port[3] = NULL ;
  148.  
  149.         if( ( audio_dir = getenv( "BZ_AUDIO_DIR" ) ) == NULL &&
  150.             ( audio_dir = getenv( "BZ_DIR" ) ) == NULL ) {
  151.             audio_dir = DATA_DIR ;
  152.             }
  153.  
  154.         for( i = 0 ; i < SFX_N_SOUNDS ; i++ ) {
  155.             sound_data[i] = (short *)load_aiff_file( audio_dir, sound_file[i],
  156.                                         &sound_size[i] ) ;
  157.             }
  158.  
  159.         if( sound_data[SFX_EXPLOSION] ) {
  160.             init_explosion_data( sound_data[SFX_EXPLOSION],
  161.                                  sound_size[SFX_EXPLOSION] ) ;
  162.             }
  163.         else {
  164.             explosion_size = 0 ;
  165.             }
  166.  
  167.         if( ( sound_child = sproc( sound_handler, PR_SALL, audio_port ) ) < 0 ){
  168.             fprintf( stderr, "%s: could not sproc sound handler: %s\n",
  169.                      basename, strerror( errno ) ) ;
  170.             return( 1 ) ;
  171.             }
  172.         else {
  173.             sound_enabled = 1 ;
  174.             }
  175.         }
  176.     else {
  177.         explosion_size = 0 ;
  178.         sound_enabled = 0 ;
  179.         return( 1 ) ;
  180.         }
  181.  
  182.     return( 0 ) ;
  183. }
  184.  
  185.  
  186.  
  187. void set_volume(
  188.     int level
  189.     )
  190. {
  191.     if( level >= 0 &&
  192.         level < sizeof( gain_settings ) / sizeof( gain_settings[0] ) ) {
  193.         gain_index = level ;
  194.         curr_left_gain = curr_right_gain = gain_settings[gain_index] ;
  195.         }
  196. }
  197.  
  198.  
  199.  
  200. int toggle_sound( void )
  201. {
  202.     if( has_sound_hw && sound_child )
  203.         sound_enabled = !sound_enabled ;
  204.  
  205.     return( sound_enabled ) ;
  206. }
  207.  
  208.  
  209.  
  210. void end_sound( void )
  211. {
  212.     if( sound_child > 0 ) {
  213.         kill( sound_child, SIGKILL ) ;
  214.         }
  215.     if( has_sound_hw )
  216.         reset_audio_hw() ;
  217. }
  218.  
  219.  
  220.  
  221. static void wake_up(
  222.     int sig,
  223.     int code,
  224.     struct sigcontext *sc
  225.     )
  226. {
  227. }
  228.  
  229.  
  230.  
  231. static void reset_audio_hw( void )
  232. {
  233.     long    pvbuf[6] ;
  234.     long    buflen ;
  235.  
  236.     pvbuf[0] = AL_LEFT_SPEAKER_GAIN ;
  237.     pvbuf[1] = orig_left_gain ;
  238.     pvbuf[2] = AL_RIGHT_SPEAKER_GAIN ;
  239.     pvbuf[3] = orig_right_gain ;
  240.     pvbuf[4] = AL_OUTPUT_RATE ;
  241.     pvbuf[5] = orig_output_rate ;
  242.     buflen = 6 ;
  243.  
  244.     ALsetparams( AL_DEFAULT_DEVICE, pvbuf, buflen ) ;
  245. }
  246.  
  247.  
  248.  
  249. static void set_gain(
  250.     float l,
  251.     float r
  252.     )
  253. {
  254.     long    pvbuf[6] ;
  255.     long    buflen ;
  256.  
  257.     pvbuf[0] = AL_LEFT_SPEAKER_GAIN ;
  258.     pvbuf[1] = l * curr_left_gain ;
  259.     pvbuf[2] = AL_RIGHT_SPEAKER_GAIN ;
  260.     pvbuf[3] = r * curr_right_gain ;
  261.     pvbuf[4] = AL_OUTPUT_RATE ;
  262.     pvbuf[5] = AL_RATE_16000 ;
  263.     buflen = 6 ;
  264.  
  265.     ALsetparams( AL_DEFAULT_DEVICE, pvbuf, buflen ) ;
  266. }
  267.  
  268.  
  269.  
  270. static void sound_handler(
  271.     void *arg
  272.     )
  273. {
  274.     ALport                *ap = (ALport *)arg ;
  275.     int                    i ;
  276.     int                    empty ;
  277.     int                    next_port = 0 ;
  278.     int                    n_audio_ports ;
  279.     long                max_samps_per_frame ;
  280.     long                samps_to_play[MAX_AUDIO_PORTS] ;
  281.     long                samps_played[MAX_AUDIO_PORTS] ;
  282.     short                *sample[MAX_AUDIO_PORTS] ;
  283.     struct sigaction    act ;
  284.  
  285.     prctl( PR_TERMCHILD, 0 ) ;
  286.  
  287.     max_samps_per_frame = 0.1 * 16000. ;
  288.  
  289.     n_audio_ports = 0 ;
  290.     while( ap[n_audio_ports] != NULL ) {
  291.         sample[n_audio_ports] = 0 ;
  292.         samps_to_play[n_audio_ports] = 0 ;
  293.         n_audio_ports++ ;
  294.         }
  295.  
  296.     act.sa_handler = wake_up ;
  297.     sigemptyset( &(act.sa_mask) ) ;
  298.     act.sa_flags = 0 ;
  299.     sigaction( SIGUSR1, &act, NULL ) ;
  300.  
  301.     while( 1 ) {
  302.         if( new_sound ) {
  303.             sample[next_port] = new_sound_data ;
  304.             samps_to_play[next_port] = new_sound_size ;
  305.             samps_played[next_port] = 0 ;
  306.             new_sound = 0 ;
  307.             next_port = ( next_port + 1 ) % n_audio_ports ;
  308.             }
  309.         empty = 0 ;
  310.         for( i = 0 ; i < n_audio_ports ; i++ ) {
  311.             if( samps_to_play[i] > max_samps_per_frame ) {
  312.                 set_gain( 1., 1. ) ;
  313.                 ALwritesamps( ap[i], sample[i] + samps_played[i],
  314.                               max_samps_per_frame ) ;
  315.                 samps_played[i] += max_samps_per_frame ;
  316.                 samps_to_play[i] -= max_samps_per_frame ;
  317.                 empty = 1 ;
  318.                 }
  319.             else if( samps_to_play[i] > 0 ) {
  320.                 set_gain( 1., 1. ) ;
  321.                 ALwritesamps( ap[i], sample[i] + samps_played[i],
  322.                               samps_to_play[i] ) ;
  323.                 samps_to_play[i] = 0 ;
  324.                 }
  325.             }
  326.         if( empty == 0 ) {
  327.             pause() ;
  328.             }
  329.         }
  330. }
  331.  
  332.  
  333.  
  334. void sfx(
  335.     int sound
  336.     )
  337. {
  338.     if( audio_port[0] && sound_data[sound] && sound_enabled ) {
  339.         signal_sound( sound_data[sound], sound_size[sound] ) ;
  340.         }
  341. }
  342.  
  343.  
  344.  
  345. void explosion_sfx(
  346.     float x,
  347.     float y,
  348.     float heading
  349.     )
  350. {
  351.     int        d ;
  352.     int        a ;
  353.     int        offset = 0 ;
  354.     double    angle ;
  355.  
  356.     if( explosion_size && sound_enabled ) {
  357.         d = sqrt( x * x + y * y ) / EXP_DELTA_DEPTH ;
  358.         if( d > MAX_EXP_DEPTH - 1 )
  359.             d = MAX_EXP_DEPTH - 1 ;
  360.         angle = atan2( y, x ) + heading * ( M_PI / 180.0 ) ;
  361.         if( angle > 2.* M_PI )
  362.             angle -= 2. * M_PI ;
  363.         if( angle < 0.0 )
  364.             angle = -angle ;
  365.         if( angle > M_PI ) {
  366.             angle = 2. * M_PI - angle ;
  367.             }
  368.         if( angle > M_PI_2 ) {
  369.             angle = M_PI - angle ;
  370.             offset = 1 ;
  371.             }
  372.         a = ( angle + 0.5 * EXP_DELTA_ANGLE ) / EXP_DELTA_ANGLE ;
  373.         signal_sound( explosion_data[d][a] + offset, explosion_size ) ;
  374.         }
  375. }
  376.  
  377.  
  378.  
  379. static void signal_sound(
  380.     short *data,
  381.     long size
  382.     )
  383. {
  384.     if( sound_child ) {
  385.         new_sound_data = data ;
  386.         new_sound_size = size ;
  387.         new_sound = 1 ;
  388.         kill( sound_child, SIGUSR1 ) ;
  389.         }
  390. }
  391.  
  392.  
  393.  
  394. static ALport init_audio_port(
  395.     int all
  396.     )
  397. {
  398.     long        pvbuf[6] ;
  399.     long        buflen ;
  400.     ALconfig    audio_port_config;
  401.     ALport        ap ;
  402.  
  403.     if( all ) {
  404.         pvbuf[0] = AL_LEFT_SPEAKER_GAIN ;
  405.         pvbuf[2] = AL_RIGHT_SPEAKER_GAIN ;
  406.         pvbuf[4] = AL_OUTPUT_RATE ;
  407.         buflen = 6 ;
  408.         ALgetparams( AL_DEFAULT_DEVICE, pvbuf, buflen ) ;
  409.         curr_left_gain = orig_left_gain = pvbuf[1] ;
  410.         curr_right_gain = orig_right_gain = pvbuf[3] ;
  411.         orig_output_rate = pvbuf[5] ;
  412.  
  413.         set_gain_index( ( orig_left_gain + orig_right_gain ) / 2 ) ;
  414.         }
  415.  
  416.     /*
  417.      * configure and open audio port
  418.      */
  419.     audio_port_config = ALnewconfig();
  420.     ALsetwidth( audio_port_config, AL_SAMPLE_16 ) ;
  421.     ALsetchannels( audio_port_config, AL_STEREO ) ;
  422.  
  423.     /*
  424.      * make the ring buffer large enough to hold 0.1 sec of audio samples
  425.      */
  426.     ALsetqueuesize( audio_port_config, 16000 * 0.1 ) ;
  427.     ap = ALopenport( basename, "w", audio_port_config ) ;
  428.  
  429.     ALfreeconfig( audio_port_config ) ;
  430.  
  431.     return( ap ) ;
  432. }
  433.  
  434.  
  435.  
  436. static char *load_aiff_file(
  437.     char *dir,
  438.     char *name,
  439.     long *size
  440.     )
  441. {
  442.     int        fd ;
  443.     char    *data ;
  444.  
  445.     filename = malloc( strlen( name ) + strlen( dir ) + 2 ) ;
  446.     sprintf( filename, "%s/%s", dir, name ) ;
  447.  
  448.     if( ( fd = open( filename, O_RDONLY ) ) < 0 ) {
  449.         fprintf( stderr, "%s: can't open %s: %s\n", basename, filename,
  450.             strerror( errno ) ) ;
  451.         free( filename ) ;
  452.         return( NULL ) ;
  453.         }
  454.  
  455.     data = read_aiff_file( fd, size ) ;
  456.  
  457.     free( filename ) ;
  458.  
  459.     close( fd ) ;
  460.  
  461.     return( data ) ;
  462. }
  463.  
  464.  
  465.  
  466. static char *read_aiff_file(
  467.     int fd,
  468.     long *size
  469.     )
  470. {
  471.     int                n ;
  472.     chunk_header_t    chunk_header ;
  473.     comm_chunk_t    comm_data ;
  474.     ssnd_chunk_t    ssnd_data ;
  475.     audio_params_t    audio_params ;
  476.  
  477.     if( ( n = read_chunk_header( fd, &chunk_header ) ) != CHUNK_HEADER ) {
  478.         fprintf( stderr, "%s: failed to read FORM chunk header\n", basename ) ;
  479.         return( NULL ) ;
  480.         }
  481.  
  482.     if( strncmp( chunk_header.id, "FORM", 4 ) ) {
  483.         fprintf( stderr, "%s: couldn't find FORM chunk id\n", basename ) ;
  484.         return( NULL ) ;
  485.         }
  486.  
  487.     read_form_chunk( fd, &chunk_header ) ;
  488.  
  489.     /*
  490.      * loop on the local chunks
  491.      */
  492.     while( ( n = read_chunk_header( fd, &chunk_header ) ) != 0 ) {
  493.         if( n != CHUNK_HEADER ) {
  494.             fprintf( stderr, "%s: failed to read a chunk header\n", basename ) ;
  495.             return( NULL ) ;
  496.             }
  497.  
  498.         /* common */
  499.         if( !strncmp( chunk_header.id, "COMM", 4 ) ) {
  500.             read_comm_chunk( fd, &comm_data, &audio_params ) ;
  501.             }
  502.         /* sound data */
  503.         else if( !strncmp( chunk_header.id, "SSND", 4 ) ) {
  504.             read_ssnd_chunk( fd, &chunk_header, &ssnd_data ) ;
  505.             }
  506.         else if( ( !strncmp( chunk_header.id, "MARK", 4 ) )  /* marker */
  507.               || ( !strncmp( chunk_header.id, "INST", 4 ) )  /* instrument */
  508.               || ( !strncmp( chunk_header.id, "APPL", 4 ) )  /* appl specific */
  509.               || ( !strncmp( chunk_header.id, "MIDI", 4 ) )  /* midi data */
  510.               || ( !strncmp( chunk_header.id, "AESD", 4 ) )  /* audio  rec */
  511.               || ( !strncmp( chunk_header.id, "COMT", 4 ) )  /* comments */
  512.               || ( !strncmp( chunk_header.id, "NAME", 4 ) )  /* text */
  513.               || ( !strncmp( chunk_header.id, "AUTH", 4 ) )  /* text */
  514.               || ( !strncmp( chunk_header.id, "(c) ", 4 ) )  /* text */
  515.               || ( !strncmp( chunk_header.id, "ANNO", 4 ) )  /* text */
  516.             ) {
  517.             skip_chunk( fd, &chunk_header ) ;
  518.             }
  519.         else {
  520.             fprintf( stderr, "%s: bad chunk id  0x%02x%02x%02x%02x\n",
  521.                      basename, chunk_header.id[0],chunk_header.id[1],
  522.                      chunk_header.id[2], chunk_header.id[3]);
  523.             }
  524.         } /* while */
  525.  
  526.     return( init_audio( fd, &audio_params, &ssnd_data, &comm_data, size ) ) ;
  527. }
  528.  
  529.  
  530.  
  531. /*
  532.  * R E A D _ C H U N K _ H E A D E R
  533.  */
  534. static int read_chunk_header(
  535.     int fd,
  536.     chunk_header_t *chunk_header
  537.     )
  538. {
  539.     align_long_t    align_long ;
  540.     char            buf[CHUNK_HEADER] ;
  541.     int                i ;
  542.     int                n ;
  543.  
  544.     if( ( n = read( fd, buf, CHUNK_HEADER) ) != CHUNK_HEADER ) {
  545.         return( n ) ;
  546.         }
  547.  
  548.     for( i = 0 ; i < 4 ; i++ ) {
  549.         chunk_header->id[i] = buf[i] ;
  550.         }
  551.  
  552.     for( i = 0 ; i < 4 ; i++ ) {
  553.         align_long.b[i] = buf[i+4] ;
  554.         } 
  555.     chunk_header->size = align_long.l ;
  556.  
  557.     return( CHUNK_HEADER ) ;
  558. }
  559.  
  560.  
  561.  
  562.  
  563. static void read_form_chunk(
  564.     int fd,
  565.     chunk_header_t *chunk_header
  566.     )
  567. {
  568.     char buf[FORM_CHUNK_DATA];
  569.  
  570.     if( chunk_header->size < 0 ) {
  571.         fprintf( stderr, "%s: invalid FORM chunk data size %ld\n", basename,
  572.                             chunk_header->size ) ;
  573.         exit( 1 ) ;
  574.         }
  575.     else if( chunk_header->size == 0 ) {
  576.         fprintf( stderr, "%s: FORM chunk data size = 0\n", basename ) ;
  577.         exit( 0 ) ;
  578.         } 
  579.  
  580.     if( read( fd, buf, FORM_CHUNK_DATA ) != FORM_CHUNK_DATA ) {
  581.         fprintf( stderr, "%s: couldn't read AIFF identifier from %s\n",
  582.                             basename, filename ) ;
  583.         exit( 1 ) ;
  584.         }
  585.     if( strncmp( buf, "AIFF", 4 ) ) {
  586.         fprintf( stderr, "%s: %s does not have an AIFF identifier\n",
  587.                             basename, filename ) ;
  588.         exit(1);
  589.         }
  590. }
  591.  
  592.  
  593.  
  594. /*
  595.  * R E A D _ C O M M _ C H U N K
  596.  */
  597. static void read_comm_chunk(
  598.     int fd,
  599.     comm_chunk_t *comm_data,
  600.     audio_params_t *audio_params
  601.     )
  602. {
  603.     int n;
  604.     char *buf, *bufp;
  605.     int i;
  606.     align_short_t align_short;
  607.     align_long_t  align_long;
  608.     double tmpdouble;
  609.  
  610.     buf = malloc(COMM_CHUNK_DATA + 1); /* leave an extra loc at the end */
  611.  
  612.     if ((n = read(fd,  buf, COMM_CHUNK_DATA)) != COMM_CHUNK_DATA)
  613.     {
  614.         fprintf(stderr, 
  615.         "%s: failed to read COMM chunk data. Expected %d bytes, got %d.\n",
  616.             basename, COMM_CHUNK_DATA, n); 
  617.         exit(1);
  618.     }
  619.     bufp = buf;
  620.     for (i=0; i<2; i++)
  621.     {
  622.        align_short.b[i] = *bufp++;
  623.     }
  624.     comm_data->nchannels = align_short.s;
  625.     for (i=0; i<4; i++) 
  626.     { 
  627.        align_long.b[i]  = *bufp++;
  628.     }
  629.     comm_data->nsampframes = align_long.l;
  630.     for (i=0; i<2; i++)
  631.     {
  632.        align_short.b[i] = *bufp++;
  633.     }
  634.     comm_data->sampwidth = align_short.s; 
  635.  
  636.     /*
  637.      * the sample rate value from the common chunk is an 80-bit IEEE extended
  638.      * floating point number:
  639.      * [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
  640.      *
  641.      */
  642.     tmpdouble = ConvertFromIeeeExtended(bufp);
  643.     bufp+=10;
  644.     comm_data->samprate = (long)tmpdouble;
  645.  
  646.     switch (comm_data->samprate)
  647.     {
  648.         case 48000:
  649.         audio_params->samprate = AL_RATE_48000;        
  650.         break;
  651.     case 44100:
  652.         audio_params->samprate = AL_RATE_44100;
  653.         break;
  654.     case 32000:
  655.         audio_params->samprate = AL_RATE_32000;
  656.         break;
  657.     case 22050:
  658.         audio_params->samprate = AL_RATE_22050;
  659.         break;
  660.     case 16000:
  661.         audio_params->samprate = AL_RATE_16000;
  662.         break;
  663.     case 11025:
  664.         audio_params->samprate = AL_RATE_11025;
  665.         break;
  666.     case  8000:
  667.         audio_params->samprate = AL_RATE_8000;
  668.         break;
  669.         default:
  670.                 fprintf(stderr,"%s: can't set output sample rate to %ld\n",
  671.                             basename, comm_data->samprate);
  672.         audio_params->samprate = AL_RATE_48000;        
  673.     }
  674.  
  675.     switch (comm_data->nchannels)
  676.     {
  677.     case 1:
  678.         audio_params->nchannels = AL_MONO;
  679.         break;
  680.     case 2:
  681.         audio_params->nchannels = AL_STEREO;
  682.         break;
  683.     default:
  684.         fprintf(stderr, "%s: can't handle %d channels per frame\n",
  685.                     basename, comm_data->nchannels);
  686.         audio_params->nchannels = AL_STEREO;
  687.     }
  688.     switch (comm_data->sampwidth)
  689.     {
  690.     case 8:
  691.          audio_params->sampwidth = AL_SAMPLE_8;
  692.         break;
  693.     case 16:
  694.          audio_params->sampwidth = AL_SAMPLE_16;
  695.         break;
  696.     case 24:
  697.          audio_params->sampwidth = AL_SAMPLE_24;
  698.         break;
  699.     default:
  700.         fprintf(stderr, "%s: unsupported sample width %d bits\n",
  701.             basename, comm_data->nchannels);
  702.          audio_params->sampwidth = AL_SAMPLE_16;
  703.     }
  704.     free(buf);
  705. }
  706.  
  707.  
  708.  
  709. static void read_ssnd_chunk(
  710.     int fd,
  711.     chunk_header_t *chunk_header,
  712.     ssnd_chunk_t *ssnd_data
  713.     )
  714. {
  715.     char buf[SSND_CHUNK_DATA];
  716.     int i;
  717.     align_long_t align_long;
  718.  
  719.     read(fd, buf, SSND_CHUNK_DATA);
  720.  
  721.     for (i=0; i<4; i++)
  722.     {
  723.         align_long.b[i] = buf[i];
  724.     }
  725.     ssnd_data->offset = align_long.l;
  726.     for (i=0; i<4; i++)
  727.     {
  728.         align_long.b[i] = buf[i+4];
  729.     }
  730.     ssnd_data->blocksize = align_long.l;
  731.     /*
  732.      * store the offset to the beginning of the audio sample data so that
  733.      * we can come back and play it later
  734.      */ 
  735.     ssnd_data->file_position = lseek(fd, 0, SEEK_CUR);
  736.     ssnd_data->sample_area_bytes = chunk_header->size - 2*sizeof(long);
  737.     if (chunk_header->size %2 == 1)
  738.     {
  739.         ssnd_data->sample_area_bytes++;
  740.     }
  741.  
  742.     /*
  743.      * move the fileptr to the end of the chunk
  744.      */
  745.     lseek(fd, ssnd_data->sample_area_bytes, SEEK_CUR);
  746. }
  747.  
  748.  
  749.  
  750. /*
  751.  * S K I P _ C H U N K
  752.  */
  753. static void skip_chunk(
  754.     int fd,
  755.     chunk_header_t *chunk_header
  756.     )
  757. {
  758.     char id[5];
  759.     int s;
  760.  
  761.     strncpy(id, chunk_header->id, 4);
  762.     id[4] = '\0'; 
  763.  
  764.     /* skip the pad byte, if necessary */
  765.     s = ((chunk_header->size % 2) == 1) ? chunk_header->size + 1 : chunk_header->size;
  766.     lseek(fd, s, SEEK_CUR);
  767. }
  768.  
  769.  
  770.  
  771.  
  772. /*
  773.  * C O N V E R T   F R O M   I E E E   E X T E N D E D  
  774.  */
  775.  
  776. /* 
  777.  * Copyright (C) 1988-1991 Apple Computer, Inc.
  778.  * All rights reserved.
  779.  *
  780.  * Warranty Information
  781.  *  Even though Apple has reviewed this software, Apple makes no warranty
  782.  *  or representation, either express or implied, with respect to this
  783.  *  software, its quality, accuracy, merchantability, or fitness for a
  784.  *  particular purpose.  As a result, this software is provided "as is,"
  785.  *  and you, its user, are assuming the entire risk as to its quality
  786.  *  and accuracy.
  787.  *
  788.  * This code may be used and freely distributed as long as it includes
  789.  * this copyright notice and the above warranty information.
  790.  
  791.  * Machine-independent I/O routines for IEEE floating-point numbers.
  792.  *
  793.  * NaN's and infinities are converted to HUGE_VAL or HUGE, which
  794.  * happens to be infinity on IEEE machines.  Unfortunately, it is
  795.  * impossible to preserve NaN's in a machine-independent way.
  796.  * Infinities are, however, preserved on IEEE machines.
  797.  *
  798.  * These routines have been tested on the following machines:
  799.  *    Apple Macintosh, MPW 3.1 C compiler
  800.  *    Apple Macintosh, THINK C compiler
  801.  *    Silicon Graphics IRIS, MIPS compiler
  802.  *    Cray X/MP and Y/MP
  803.  *    Digital Equipment VAX
  804.  *
  805.  *
  806.  * Implemented by Malcolm Slaney and Ken Turkowski.
  807.  *
  808.  * Malcolm Slaney contributions during 1988-1990 include big- and little-
  809.  * endian file I/O, conversion to and from Motorola's extended 80-bit
  810.  * floating-point format, and conversions to and from IEEE single-
  811.  * precision floating-point format.
  812.  *
  813.  * In 1991, Ken Turkowski implemented the conversions to and from
  814.  * IEEE double-precision format, added more precision to the extended
  815.  * conversions, and accommodated conversions involving +/- infinity,
  816.  * NaN's, and denormalized numbers.
  817.  */
  818.  
  819. # define UnsignedToFloat(u)    \
  820.      (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
  821.  
  822. /****************************************************************
  823.  * Extended precision IEEE floating-point conversion routine.
  824.  ****************************************************************/
  825.  
  826. static double ConvertFromIeeeExtended(
  827.     char *bytes
  828.     )
  829. {
  830.     double            f ;
  831.     long            expon ;
  832.     unsigned long    hiMant ;
  833.     unsigned long    loMant ;
  834.     
  835.     expon = ( ( bytes[0] & 0x7F ) << 8 ) | ( bytes[1] & 0xFF ) ;
  836.     hiMant = ( (unsigned long)( bytes[2] & 0xFF ) << 24 )
  837.            | ( (unsigned long)( bytes[3] & 0xFF ) << 16 )
  838.            | ( (unsigned long)( bytes[4] & 0xFF ) << 8  )
  839.            | ( (unsigned long)( bytes[5] & 0xFF ) ) ;
  840.     loMant = ( (unsigned long)( bytes[6] & 0xFF ) << 24 )
  841.            | ( (unsigned long)( bytes[7] & 0xFF ) << 16 )
  842.            | ( (unsigned long)( bytes[8] & 0xFF ) << 8  )
  843.            | ( (unsigned long)( bytes[9] & 0xFF ) ) ;
  844.  
  845.     if( expon == 0 && hiMant == 0 && loMant == 0 ) {
  846.         f = 0;
  847.         }
  848.     else {
  849.         if( expon == 0x7FFF ) {    /* Infinity or NaN */
  850.             f = HUGE_VAL;
  851.             }
  852.         else {
  853.             expon -= 16383;
  854.             f  = ldexp( UnsignedToFloat( hiMant ), expon-=31 ) ;
  855.             f += ldexp( UnsignedToFloat( loMant ), expon-=32 ) ;
  856.             }
  857.         }
  858.  
  859.     if( bytes[0] & 0x80 )
  860.         return( -f ) ;
  861.     else
  862.         return( f ) ;
  863. }
  864.  
  865.  
  866.  
  867. /*
  868.  * I N I T _ A U D I O
  869.  */
  870. static char *init_audio(
  871.     int fd,
  872.     audio_params_t *audio_params,
  873.     ssnd_chunk_t *ssnd_data,
  874.     comm_chunk_t *comm_data,
  875.     long *size
  876.     )
  877. {
  878.     char    *buf ;
  879.     int        bytes_read ;
  880.  
  881.     /*
  882.      * decide what size blocks of samples we should read from the
  883.      * AIFF file and pass to ALwritesamps
  884.      */
  885.     switch( audio_params->sampwidth ) {
  886.         default :
  887.         case AL_SAMPLE_8 :
  888.             fprintf( stderr, "%s: sound file %s is not 16 bytes/sample\n",
  889.                 basename, filename ) ;
  890.             return( NULL ) ;
  891.             break ;
  892.  
  893.         case AL_SAMPLE_16 :
  894.             bytes_per_samp = 2 ;
  895.             break ;
  896.         }
  897.  
  898.     switch( audio_params->nchannels ) {
  899.         default :
  900.         case AL_MONO :
  901.             fprintf( stderr, "%s: sound file %s is not in stereo\n",
  902.                 basename, filename ) ;
  903.             return( NULL ) ;
  904.             break ;
  905.       
  906.         case AL_STEREO :
  907.             samps_per_frame = 2 ;
  908.             break ;
  909.         }
  910.  
  911.     switch( audio_params->samprate ) {
  912.         default :
  913.         case AL_RATE_48000 :
  914.         case AL_RATE_44100 :
  915.         case AL_RATE_32000 :
  916.         case AL_RATE_22050 :
  917.         case AL_RATE_11025 :
  918.         case AL_RATE_8000 :
  919.             fprintf( stderr, "%s: sound file %s is not sampled at 16KHz\n",
  920.                 basename, filename ) ;
  921.             return( NULL ) ;
  922.             break ;
  923.  
  924.         case AL_RATE_16000 :
  925.             frames_per_sec = 16000 ;
  926.             break ;
  927.     }
  928.  
  929.     *size = comm_data->nsampframes * samps_per_frame * bytes_per_samp ;
  930.  
  931.     buf = (char *)malloc( *size ) ;
  932.     lseek( fd, ssnd_data->file_position, SEEK_SET ) ;
  933.     if( ( bytes_read = read( fd, buf, *size ) ) < *size ) {
  934.         fprintf( stderr, "%s: short read on %s\n", basename, filename ) ;
  935.         *size = bytes_read ;
  936.         }
  937.  
  938.     *size /= samps_per_frame ;
  939.  
  940.     return( buf ) ;
  941. }
  942.  
  943.  
  944.  
  945. static int check_for_audio_hw( void )
  946. {
  947.     int            st = 0 ;
  948.     inventory_t    *base ;
  949.     inventory_t    *inv ;
  950.  
  951.     inv = base = getinvent() ;
  952.     while( inv != NULL ) {
  953.         /*
  954.          * Ok if any type of audio hardware available.
  955.          */
  956. #if defined( SVR3 )
  957.         if( inv->class == INV_AUDIO ) {
  958. #else
  959.         if( inv->inv_class == INV_AUDIO ) {
  960. #endif /* defined( SVR3 ) */
  961.                 st = 1 ;
  962.             }
  963.         inv = getinvent() ;
  964.         }
  965.     
  966.     if( base )
  967.         endinvent() ;
  968.  
  969.     return( st ) ;
  970. }
  971.  
  972.  
  973.  
  974. int volume_change(
  975.     int direction
  976.     )
  977. {
  978.     if( direction == 1 ) {
  979.         if( gain_index <
  980.             sizeof( gain_settings ) / sizeof( gain_settings[0] ) - 1 ) {
  981.             gain_index++ ;
  982.             }
  983.         }
  984.     else {
  985.         if( gain_index > 0 ) {
  986.             gain_index-- ;
  987.             }
  988.         }
  989.     curr_left_gain = curr_right_gain = gain_settings[gain_index] ;
  990.  
  991.     set_gain( 1., 1. ) ;
  992.  
  993.     return( gain_index ) ;
  994. }
  995.  
  996.  
  997.  
  998. static void set_gain_index(
  999.     unsigned long gain
  1000.     )
  1001. {
  1002.     int        i ;
  1003.     long    min = 256 ;
  1004.     long    diff ;
  1005.  
  1006.     for( i = 0 ; i < sizeof( gain_settings ) / sizeof( gain_settings[0] ) ;
  1007.          i++ ) {
  1008.         diff = gain - gain_settings[i] ;
  1009.         if( diff < 0 )
  1010.             diff = -diff ;
  1011.         if( diff < min ) {
  1012.             min = diff ;
  1013.             gain_index = i ;
  1014.             }
  1015.         }
  1016. }
  1017.  
  1018.  
  1019.  
  1020. static void init_explosion_data(
  1021.     short *src_data,
  1022.     long src_size
  1023.     )
  1024. {
  1025.     int        d ;
  1026.     int        a ;
  1027.     int        i ;
  1028.     int        st = 0 ;
  1029.     double    angle ;
  1030.     double    dist ;
  1031.     double    s ;
  1032.     double    x ;
  1033.     double    y ;
  1034.     double    l ;
  1035.     double    r ;
  1036.  
  1037.     for( d = 0 ; d < MAX_EXP_DEPTH && !st ; d++ ) {
  1038.         for( a = 0 ; a < MAX_EXP_ANGLE && !st ; a++ ) {
  1039.             if( ( explosion_data[d][a] = (short *)malloc(
  1040.                     ( src_size * 2 + 1 ) * sizeof( short ) ) ) == NULL ) {
  1041.                 st = 1 ;
  1042.                 }
  1043.             }
  1044.         }
  1045.  
  1046.     if( st ) {
  1047.         for( d = 0 ; d < MAX_EXP_DEPTH ; d++ ) {
  1048.             for( a = 0 ; a < MAX_EXP_ANGLE ; a++ ) {
  1049.                 if( explosion_data[d][a] )
  1050.                     free( explosion_data[d][a] ) ;
  1051.                 }
  1052.             }
  1053.         explosion_size = 0 ;
  1054.         return ;
  1055.         }
  1056.  
  1057.     for( d = 0 ; d < MAX_EXP_DEPTH ; d++ ) {
  1058.         for( a = 0 ; a < MAX_EXP_ANGLE ; a++ ) {
  1059.             angle = a * EXP_DELTA_ANGLE ;
  1060.             dist = d * EXP_DELTA_DEPTH ;
  1061.             x = cos( angle ) ;
  1062.             s = 0.5 * ( x * ABS(x) ) ;
  1063.             dist = 1. - ( dist / 1250. ) ;
  1064.             dist *= dist ;
  1065.             r = sqrt( ( 0.5 - s ) * dist ) ;
  1066.             l = sqrt( ( 0.5 + s ) * dist ) ;
  1067.             for( i = 0 ; i < 2 * src_size ; i += 2 ) {
  1068.                 explosion_data[d][a][i+0] = r * src_data[i+0] ;
  1069.                 explosion_data[d][a][i+1] = l * src_data[i+1] ;
  1070.                 }
  1071.             explosion_data[d][a][2*src_size] = 0 ;
  1072.             }
  1073.         }
  1074.     explosion_size = src_size ;
  1075. }
  1076.